/**
 * Copyright (c) 2012-2013 Nokia Corporation. All rights reserved.
 * Nokia and Nokia Connecting People are registered trademarks of Nokia Corporation. 
 * Oracle and Java are trademarks or registered trademarks of Oracle and/or its
 * affiliates. Other product and company names mentioned herein may be trademarks
 * or trade names of their respective owners. 
 * See LICENSE.TXT for license information.
 */
package com.nokia.example.fuelcalculator.view;

import com.nokia.example.fuelcalculator.Midlet;
import com.nokia.example.fuelcalculator.l10n.L10NIDs;
import com.nokia.example.fuelcalculator.l10n.Localizer;
import com.nokia.example.fuelcalculator.model.FuelConsumptionModel;
import com.nokia.example.fuelcalculator.model.ModelObject;
import com.nokia.example.fuelcalculator.utils.Commands;
import com.nokia.example.fuelcalculator.utils.Consumption;
import java.util.Date;
import javax.microedition.lcdui.Alert;
import javax.microedition.lcdui.AlertType;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.DateField;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.lcdui.Item;
import javax.microedition.lcdui.ItemStateListener;
import javax.microedition.lcdui.StringItem;
import javax.microedition.lcdui.TextField;

/**
 * This is the View that is shown when "Add filling" command is selected.
 */
public final class AddFillingView
    implements CommandListener, View {
    
    private static final int BOTH_FIELDS_INVALID_ALERT = 1;
    private static final int FUEL_FIELD_INVALID_ALERT = 2;
    private static final int DISTANCE_INVALID_ALERT = 3;
    
    private Localizer localizer;
    private ViewManager viewManager;
    private FuelConsumptionModel model;
    
    private Form form;
    private DateField dateField;
    private TextField fuelField;
    private TextField distanceField;
    private StringItem consumptionField;
    
    /**
     * Constructor.
     * @param viewManager 
     */
    public AddFillingView(ViewManager viewManager) {       
        this.localizer = Localizer.getInstance();
        this.viewManager = viewManager;
        this.model = Midlet.getInstance().getFuelConsumptionModel();
        
        this.form = new Form(
                localizer.getString(L10NIDs.ADD_FILLING_VIEW_TITLE));
        layoutForm();
        
        form.addCommand(Commands.SAVE_FILLING_ACTION);       
        form.addCommand(Commands.GOTO_ABOUT_VIEW);
        form.addCommand(Commands.GOTO_HELP_VIEW);
        form.addCommand(Commands.CLEAR_FIELDS_ACTION);
        form.addCommand(Commands.BACK_FROM_ADD_FILLING);
        form.setCommandListener(this);
    }

    /**
     * @see fuelconsumption.view.View#updateUI()
     */
    public void updateUI() {
        clearFields();
    }

    /**
     * @see fuelconsumption.view.View#updateUI()
     */
    public Displayable getDisplayable() {
        return form;
    }

    /**
     * @see javax.microedition.lcdui.CommandListener#commandAction(Command, Displayable)
     */
    public void commandAction(Command c, Displayable d) {
        if (c == Commands.SAVE_FILLING_ACTION) {
            boolean fuelValid = isFuelFieldValid();
            boolean distanceValid = isDistanceFieldValid();
            
            if ((!fuelValid) && (!distanceValid)) {
                showAlert(BOTH_FIELDS_INVALID_ALERT);
            } else if (!fuelValid) {
                showAlert(FUEL_FIELD_INVALID_ALERT);
            } else if (!distanceValid) {
                showAlert(DISTANCE_INVALID_ALERT);
            } else {
                ModelObject obj = ModelObject.createModelObject(
                        getDateValue(), getFuelValue(), getDistanceValue());
                model.addObject(obj);
                viewManager.showEnterView();
            }
        } else if (c == Commands.CLEAR_FIELDS_ACTION) {
            clearFields();
        } else {
            viewManager.commandAction(c, d);
        }
        
    }

    private void layoutForm() {
        dateField = new DateField(
               localizer.getString(L10NIDs.ADD_FILLING_VIEW_DATE_FIELD_TITLE),
               DateField.DATE);
        fuelField = new TextField(
               localizer.getString(L10NIDs.ADD_FILLING_VIEW_FUEL_FIELD_TITLE),
               "",
               30,
               TextField.DECIMAL);
        distanceField = new TextField(
               localizer.getString(L10NIDs.ADD_FILLING_VIEW_DISTANCE_FIELD_TITLE),
               "",
               30, 
               TextField.DECIMAL);
        consumptionField = new StringItem(
                localizer.getString(L10NIDs.ADD_FILLING_VIEW_CONSUMPTION_FIELD_TITLE),
                "");
        
        clearFields();
        
        form.append(dateField);
        form.append(fuelField);
        form.append(distanceField);
        form.append(consumptionField);       
        
        form.setItemStateListener(new ItemStateListener() {
            public void itemStateChanged(Item item) {
                if ((item == fuelField) || (item == distanceField)) {
                    calculateConsumption();
                }
            }
        });
    }
    
    private void clearFields() {
        dateField.setDate(new Date());
        fuelField.setString("");
        distanceField.setString("");
        consumptionField.setText(
            localizer.getString(
                L10NIDs.ADD_FILLING_VIEW_CONSUMPTION_FIELD_TEXT_UNKNOWN));
    }
    
    private void calculateConsumption() {
        if (isFuelFieldValid() && isDistanceFieldValid()) {
            double fuel = getFuelValue();
            int distance = getDistanceValue();
            
            consumptionField.setText(
                    localizer.formatConsumption(Consumption.calculate(fuel, distance)) + 
                    " " +
                    localizer.getString(L10NIDs.CONSUMPTION_UNIT));

        } else {
            consumptionField.setText(
            localizer.getString(
                L10NIDs.ADD_FILLING_VIEW_CONSUMPTION_FIELD_TEXT_UNKNOWN));
        }
    
    }
    
    private void showAlert(int alertType) {
        Alert dummyAlert = new Alert(
                localizer.getString(L10NIDs.ALERT_TITLE),
                "",
                null,
                AlertType.CONFIRMATION);
        dummyAlert.addCommand(Commands.OK_FROM_ALERT);
        dummyAlert.addCommand(Commands.BACK_FROM_ALERT);
        //notice that we do not have to add a specific command listener
        //for these alerts.

        switch (alertType) {
            case BOTH_FIELDS_INVALID_ALERT:
                dummyAlert.setString(
                        localizer.getString(L10NIDs.ALERT_FUEL_AND_DISTANCE_TEXT));
                break;
            case FUEL_FIELD_INVALID_ALERT:
                dummyAlert.setString(localizer.getString(L10NIDs.ALERT_FUEL_TEXT));
                break;
            case DISTANCE_INVALID_ALERT:
                dummyAlert.setString(localizer.getString(L10NIDs.ALERT_DISTANCE_TEXT));
                break;
            default:
                break;       
        }
        viewManager.showAlert(dummyAlert, this);
    }
    
    private boolean isFuelFieldValid() {
        boolean valid;
        try {
            getFuelValue();
            valid = fuelFieldHasAtMostTwoDecimals();
        } catch (NumberFormatException nfe) {
            valid = false;
        }
        return valid;
    }
    
    private boolean isDistanceFieldValid() {
        boolean valid = true;
        try {
            getDistanceValue();
        } catch (NumberFormatException nfe) {
            valid = false;
        }
        return valid;
    }
    
    private long getDateValue() {
        return dateField.getDate().getTime();
    }
    
    private double getFuelValue() {
        String fuelFieldString = fuelField.getString();
        return Double.parseDouble(fuelFieldString);
    }

    private int getDistanceValue() {
        String distanceValue = distanceField.getString();
        return Integer.parseInt(distanceValue);
    }
    
    private boolean fuelFieldHasAtMostTwoDecimals() {
        final char DECIMAL_SEPARATOR = '.';
        String fuelFieldString = fuelField.getString();
        int indexOfSeparator = fuelFieldString.indexOf(DECIMAL_SEPARATOR);
        
        // check whether there is a decimal separator or not
        if (indexOfSeparator == -1) {
            return true;
        }
        
        // check whether there are more than one decimal separators
        if (indexOfSeparator != fuelFieldString.lastIndexOf(DECIMAL_SEPARATOR)) {
            return false;
        }
        
        // check whether there is a digit or digits before decimal separator
        if (indexOfSeparator == 0) {
            return false;
        }
        
        // check whether there is at least one digit after decimal separator
        if((fuelFieldString.length()-1) == indexOfSeparator) {
            return false;
        }
        
        // check whether there is at most two digits after decimal separator
        if (((fuelFieldString.length() - 1) - indexOfSeparator) > 2) {
            return false;
        }
        
        return true;
    }
}
